package com.tianji.promotion.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.promotion.constants.PromotionConstants;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.CouponScope;
import com.tianji.promotion.domain.po.UserCoupon;
import com.tianji.promotion.domain.query.CouponQuery;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.domain.vo.CouponVO;
import com.tianji.promotion.enums.CouponStatus;
import com.tianji.promotion.enums.ObtainType;
import com.tianji.promotion.enums.UserCouponStatus;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.service.ICouponScopeService;
import com.tianji.promotion.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.service.IExchangeCodeService;
import com.tianji.promotion.service.IUserCouponService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author liuchun
 * @since 2024-10-23
 */
@Service
@Slf4j
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {


    @Autowired
    private ICouponScopeService couponScopeService;

    @Autowired
    private IExchangeCodeService exchangeCodeService;

    @Autowired
    private IUserCouponService userCouponService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    @Transactional
    public void addCoupons(CouponFormDTO couponFormDTO) {
        //拷贝属性
        Coupon coupon = BeanUtils.copyBean(couponFormDTO, Coupon.class);
        this.save(coupon);
        //判断是否限定了范围
        if (!coupon.getSpecific()){
            return ;
        }
        //限定了范围
        if(CollUtils.isEmpty(couponFormDTO.getScopes())){
            throw new BizIllegalException("优惠券使用范围为空!");
        }
        //保存范围
        List<CouponScope> scopeList = couponFormDTO.getScopes().stream()
                .map(bizId -> new CouponScope().setBizId(bizId).setCouponId(coupon.getId()).setType(1))
                .collect(Collectors.toList());
        couponScopeService.saveBatch(scopeList);
    }

    //分页查询优惠券
    @Override
    public PageDTO<CouponPageVO> selectCouponsPage(CouponQuery query) {
        //获取一些参数
        //Integer pageNo = query.getPageNo();
        //Integer pageSize = query.getPageSize();
        String name = query.getName();
        Integer type = query.getType();
        Integer status = query.getStatus();
        Page<Coupon> page = lambdaQuery().eq(type != null, Coupon::getDiscountType, type)
                .eq(status != null, Coupon::getStatus, status)
                .like(StrUtil.isNotBlank(name), Coupon::getName, name)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<Coupon> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }
        List<CouponPageVO> vos = BeanUtils.copyList(records, CouponPageVO.class);
        //返回
        return PageDTO.of(page, vos);
    }

    //发放优惠券
    @Override
    @Transactional
    public void issueCoupons(Long id, CouponIssueFormDTO dto) {
        log.info("发放优惠券线程，{}", Thread.currentThread().getName());
        //参数校验
         if (id == null || !id.equals(dto.getId())){
             throw new BizIllegalException("优惠券id不为空");
         }
         //查询优惠券
         Coupon coupon = getById(id);
         if (coupon == null){
             throw new BizIllegalException("优惠券不存在");
         }
         if (!coupon.getStatus().equals(CouponStatus.PAUSE) && !coupon.getStatus().equals(CouponStatus .DRAFT)){
             throw new BizIllegalException("优惠券状态不正确");
         }
        LocalDateTime beginTime = dto.getIssueBeginTime();
        LocalDateTime now = LocalDateTime.now();
        //用于标识是否是立即发放
        boolean isBegin = beginTime == null || !beginTime.isAfter(now);

        Coupon c = BeanUtils.copyBean(dto, Coupon.class);
        //立即发放
        if(isBegin){
            c.setStatus(CouponStatus.ISSUING);
            c.setIssueBeginTime(now);
        }else{
            c.setStatus(CouponStatus.UN_ISSUE);
        }
        updateById(c);

        //对于立刻发放的优惠券，将相关信息存入Redis
        if (isBegin) {
            String key = PromotionConstants.COUPON_CACHE_KEY_PREFIX + coupon.getId();//prs:coupon:优惠券id
            HashMap<String, String> couponsInfo = new HashMap<>();
            couponsInfo.put("issueBeginTime", String.valueOf(DateUtils.toEpochMilli(now)));
            couponsInfo.put("issueEndTime", String.valueOf(DateUtils.toEpochMilli(dto.getIssueEndTime())));
            couponsInfo.put("totalNum", String.valueOf(coupon.getTotalNum()));
            couponsInfo.put("userLimit", String.valueOf(coupon.getUserLimit()));
            redisTemplate.opsForHash().putAll(key, couponsInfo);
        }
        // 兑换码的生成
        if(coupon.getStatus() ==CouponStatus.DRAFT && coupon.getObtainWay() ==ObtainType.ISSUE){
            //log.info("1111111111111");
            coupon.setIssueEndTime(c.getIssueEndTime());
            exchangeCodeService.asyncCreateExchangeCode(coupon);
        }
    }

    //查询所有发放中的优惠券
//    public List<CouponVO> listAllIssuingCoupons() {
//        //获取当前用户
//        Long userId = UserContext.getUser();
//        //发放中、手动领取
//        List<Coupon> couponList = lambdaQuery().eq(Coupon::getStatus, CouponStatus.ISSUING)
//                .eq(Coupon::getObtainWay, ObtainType.PUBLIC).list();
//        if (CollUtils.isEmpty(couponList)){
//            return CollUtils.emptyList();
//        }
//        //将优惠券剩余信息封装
//        Map<Long, Integer> map = couponList.stream().collect(Collectors.toMap(Coupon::getId, c->(c.getTotalNum()-c.getIssueNum())));
//        //用户已经领取，尚未使用的券，如果有，显示去使用
//        QueryWrapper<UserCoupon> wrapper = new QueryWrapper<>();
//        //属性拷贝
//        List<CouponVO> vos = BeanUtils.copyList(couponList, CouponVO.class);
//        //优惠券有剩余且用户领取未超过上限
//        for (CouponVO vo : vos) {
//            //优惠券id
//            Long id = vo.getId();
//            if(map.get(id) > 0){
//                vo.setAvailable(true);
//            }else {
//                vo.setAvailable(false);
//            }
//            wrapper.eq("coupon_id", id);
//            wrapper.eq("user_id", userId);
//            wrapper.eq("status", UserCouponStatus.UNUSED);
//            List<UserCoupon> list = userCouponService.list(wrapper);
//            if (CollUtils.isEmpty(list)){
//                vo.setReceived(false);
//            }else {
//                vo.setReceived(true);
//            }
//        }
//        return vos;
//    }

    //查询所有发放中的优惠券
    @Override
    public List<CouponVO> listAllIssuingCoupons() {
        //获取用户id
        Long userId = UserContext.getUser();
        //发放中、手动领取
        List<Coupon> couponList = lambdaQuery().eq(Coupon::getStatus, CouponStatus.ISSUING)
                .eq(Coupon::getObtainWay, ObtainType.PUBLIC).list();
        if (CollUtils.isEmpty(couponList)){
            return CollUtils.emptyList();
        }
        //正在发放中的优惠券id集合
        Set<Long> couponIds = couponList.stream().map(Coupon::getId).collect(Collectors.toSet());
        //当前用户针对正在发放的优惠券领取记录
        List<UserCoupon> list = userCouponService.lambdaQuery()
                .eq(UserCoupon::getUserId, userId)
                .in(UserCoupon::getCouponId, couponIds)
                .list();
        //针对当前用户，统计每一个券，已领取数量
        Map<Long, Long> issueMap = list.stream().collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));
        //针对当前用户，每一个券，已经领取未使用的数量
        Map<Long, Long> unUserMap = list.stream().filter(c -> c.getStatus() == UserCouponStatus.UNUSED).collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));

        List<CouponVO> vos = new ArrayList<>(couponList.size());
        for (Coupon c : couponList) {
            //优惠券id
            Long id = c.getId();
            CouponVO vo = BeanUtils.copyBean(c, CouponVO.class);
            boolean available = c.getTotalNum() > c.getIssueNum() && issueMap.getOrDefault(id,0L).intValue() < c.getUserLimit();
            boolean received = unUserMap.getOrDefault(id,0L) > 0;
            vo.setAvailable(available);
            vo.setReceived(received);
        }
        return vos;
    }
}
